# -*- coding: utf-8 -*-

def log(*args):
    print args[0],':) ',args[1:]
    pass


# 继承 ---> super(--, self).__init__
class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

class Teacher(Person):
    def __init__(self, name, gender, course):
        super(Teacher, self).__init__(name, gender)
        self.course = course

t = Teacher('Alice', 'Female', 'English')
log(u'继承',t.name,t.course)

# 判断类型 isinstance
log(u'判断类型', isinstance(t, Person), isinstance(t, Teacher))


# 多态
# Python提供了open()函数来打开一个磁盘文件，
# 并返回 File 对象。File对象有一个read()方法可以读取文件内容
# import json
# f = open('/path/to/file.json', 'r')
# print json.load(f)
#
# json.load()并不一定要从一个File对象读取内容。
# 任何对象，只要有read()方法，就称为File-like Object，
# 都可以传给json.load()。
# example
import json
class Students(object):
    def read(self):
        return r'["Tim", "Bob", "Alice"]'
s = Students()
print json.load(s)


# 多重继承 mixin
class A(object):
    pass
class B(object):
    pass
class C(A, B):
    def __init__(self, a, b):
        A.__init__(self, a)
        B.__init__(self, b)


# 获取更多对象信息
# 动态的为对象添加更多属性 getattr() 和 setattr( )
# example
class Person(object):
    def __init__(self, name, gender, **kw):
        self.name = name
        self.gender = gender
        for k, v in kw.iteritems():
            setattr(self, k, v)
p = Person('Bob', 'Male', age=18, course='Python')
print p.age
print p.course
print getattr(p, 'name', 'Adam')

# type() 返回对象的类型
print type(p)

# dir() 能够遍历对象的所有属性
# print dir(123)


# python 中的特殊方法
# Python 定义了__str__()和__repr__()两种方法，
# __str__() 用于显示给用户，
# __repr__() 用于显示给开发人员。
class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender
class Student(Person):
    def __init__(self, name, gender, score):
        super(Student, self).__init__(name, gender)
        self.score = score
    def __str__(self):
        return '(Student: %s, %s, %s)' % (self.name, self.gender, self.score)
    __repr__ = __str__
s = Student('Bob', 'male', 88)
print s


# __cmp__() 排序
# 如果 self 应该排在前面，就返回 -1，如果 s 应该排在前面，就返回1
class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def __str__(self):
        return '(%s: %s)' % (self.name, self.score)
    __repr__ = __str__
    def __cmp__(self, s):
        if self.score > s.score:
            return -1
        elif self.score < s.score:
            return 1
        else:
            if self.name < s.name:
                return -1
            elif self.name > s.name:
                return 1
            return 0
L = [Student('Tim', 99), Student('Bob', 88), Student('Alice', 99)]
print sorted(L)


# __len__
# 计算斐波那契额数列 ❤
# ----------
# t = a
# a = b
# b = t + b
# ----------
# a,b = b,a+b
# 1)a=b=1,b=a+b=1
class Fib(object):
    # def __init__(self, num):
    #     L = [0,1]
    #     for i in range(num-2):
    #         L.append(L[-1]+L[-2])
    #     self.numbers=L
    def __init__(self, num):
        a, b, L = 0, 1, []
        for n in range(num):
            L.append(a)
            a, b = b, a + b
        self.numbers = L

    def __str__(self):
        return str(self.numbers)
    __repr__ = __str__
    def __len__(self):
        return len(self.numbers)
f = Fib(10)
print f
print len(f)


# 实现对象之间的运算方法 ❤
# @example
# 实现有理数之间运算 分数
def gcd(a, b):
    while b:
        a, b=b ,a % b
    return a
class Rational(object):
    def __init__(self, p, q):
        self.p = p
        self.q = q
    def __add__(self, r):
        return Rational(self.p * r.q + self.q * r.p, self.q * r.q)
    def __sub__(self, r):
        return Rational(self.p * r.q - self.q * r.p, self.q * r.q)
    def __mul__(self, r):
        return Rational(self.p * r.p, self.q * r.q)
    def __div__(self, r):
        return Rational(self.p * r.q, self.q * r.p)
    def __str__(self):
        g = gcd(self.p, self.q)
        return '%s/%s' % (self.p / g, self.q / g)
    __repr__ = __str__

r1 = Rational(1, 2)
r2 = Rational(1, 4)
print r1 + r2
print r1 - r2
print r1 * r2
print r1 / r2


# 实现类型转换
class Rational(object):
    def __init__(self, p, q):
        self.p = p
        self.q = q

    def __int__(self):
        return self.p // self.q

    def __float__(self):
        return self.p*1.0/self.q

print int(Rational(7, 2))
print float(Rational(1, 3))



# property --> 实现get set 方法
# 如果没有定义set方法，这时为只读属性
# example
class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    @property
    def score(self):
        return self.__score
    @score.setter
    def score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score
    @property
    def grade(self):
        s = self.__score
        if s >= 80:
            return 'A'
        elif s < 60:
            return 'C'
        else:
            return 'B'

s = Student('Bob', 59)
print s.grade
s.score = 60
print s.grade
s.score = 99
print s.grade


# 限制属性列表 __slots__
class Person(object):
    __slots__ = ('name', 'gender')
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

class Student(Person):
    __slots__ = ('name','gender','score')
    def __init__(self, name, gender, score):
        Person.__init__(self, name, gender)
        self.score = score

s = Student('Bob', 'male', 59)
s.name = 'Tim'
s.score = 99
print s.score


# __call__ 让一个实例变成一个可调用的对象
class Fib(object):
    def __call__(self, num):
        a, b, L = 0, 1, []
        for i in range(num):
            L.append(a)
            a, b = b, a + b
        return L
f = Fib()
print f(10)
